package vip.xiaonuo.hontu.issued.util;

import java.util.Random;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import javax.net.ssl.*;
import java.io.File;
import java.net.URLEncoder;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import vip.xiaonuo.core.exception.ServiceException;
;

@Slf4j
public class OkHttpUtil {

    private static final byte[] LOCKER = new byte[0];
    private static OkHttpUtil instance;
    private static OkHttpUtil httpsInstance;
    private OkHttpClient okHttpClient;

    private OkHttpClient getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            TrustAllManager trustAllManager = new TrustAllManager();
            TrustManager[] trustManagers = {trustAllManager};
            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustManagers, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, trustAllManager);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
//            builder.addNetworkInterceptor(new HTOkHttpInterceptor()).build();
            return builder.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private OkHttpUtil(boolean https) {
        OkHttpClient.Builder builder;
        if (https) {
            builder = getUnsafeOkHttpClient().newBuilder();
        } else {
            builder = new OkHttpClient.Builder();
        }
        okHttpClient = builder
                // 10秒连接超时
                .connectTimeout(10, TimeUnit.SECONDS)
                // 写入超时
                .writeTimeout(900, TimeUnit.SECONDS)
                // 读取超时
                .readTimeout(900, TimeUnit.SECONDS).build();
    }

    public static OkHttpUtil getInstance() {
        if (instance == null) {
            synchronized (LOCKER) {
                if (instance == null) {
                    instance = new OkHttpUtil(false);
                }
            }
        }
        return instance;
    }

    /**
     * true -https false -http
     *
     * @param https
     * @return
     */
    public static OkHttpUtil getInstance(boolean https) {
        if (!https) {
            return getInstance();
        }
        if (httpsInstance == null) {
            synchronized (LOCKER) {
                if (httpsInstance == null) {
                    httpsInstance = new OkHttpUtil(https);
                }
            }
        }
        return httpsInstance;
    }

    public String doPostFormMultipart(String targetUrl, String fileUrl, Map<String, String> headers) {
        if (isBlankUrl(targetUrl) || isBlankUrl(fileUrl)) {
            return null;
        }
        Request request = getRequestForPostFormMultipart(targetUrl, fileUrl, headers);
        return commonRequest(request);
    }

    private Boolean isBlankUrl(String url) {
        if (StringUtils.isBlank(url)) {
            log.info("url is not blank");
            return true;
        } else {
            return false;
        }
    }

    private String commonRequest(Request request) {
        String re = "";
        try (Response response = HTHttpUtil.getInstance().execute(request)) {
            if (response.isSuccessful()) {
                re = response.body().string();
                log.info("request url:{};response:{}", request.url().toString(), re);
            } else {
                log.info("request failure url:{};message:{}", request.url().toString(), response.message());
                throw new Exception("code:" + response.code() + "request failure url:" + request.url().toString()
                        + ";message:" + response.message());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("request execute failure", e);
            throw new ServiceException(500, "request execute failure");
        }
        return re;
    }

    private Request getRequestForPostFormMultipart(String serverUrl, String fileUrl, Map<String, String> headers) {
        if (headers == null) {
            headers = new HashMap<>();
        }
        File file = new File(fileUrl);//文件路径(本地)
        String filename = file.getName();
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        builder.addFormDataPart("file", filename, RequestBody.create(MediaType.parse("multipart/form-data"), file));
        return new Request.Builder()
                .url(serverUrl)
                .post(builder.build())
                .addHeader("Content-Type", "multipart/form-data")
                //签名
                .header("cappkey", headers.get("cappkey"))
                .header("ctimestamp", headers.get("ctimestamp"))
                .header("cnonce", headers.get("cnonce"))
                .header("csign", headers.get("csign"))
                .build();
    }

    private Request getRequestForGet(String url, HashMap<String, String> params) {
        Request request = new Request.Builder().url(getUrlStringForGet(url, params)).build();
        return request;
    }

    private String getUrlStringForGet(String url, HashMap<String, String> params) {
        StringBuilder urlBuilder = new StringBuilder();
        urlBuilder.append(url);
        urlBuilder.append("?");
        if (params != null && params.size() > 0) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                try {
                    urlBuilder.append("&").append(entry.getKey()).append("=")
                            .append(URLEncoder.encode(entry.getValue(), "UTF-8"));
                } catch (Exception e) {
                    urlBuilder.append("&").append(entry.getKey()).append("=").append(entry.getValue());
                }
            }
        }
        return urlBuilder.toString();
    }

    public static class TrustAllManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }


    public static String getStringRandom() {
        Random random = new Random();
        //把随机生成的数字转成字符串
        String str = String.valueOf(random.nextInt(9));
        for (int i = 0; i < 5; i++) {
            str += random.nextInt(9);
        }
        return str;
    }

    public static void main(String[] args) {
        //服务端上传接口，假设鸿图服务器地址为：10.171.16.76，以图片上传接口为例，如下：
        String targetUrl = "http://10.171.16.76/v1/api/person/uploadImage";
        //本地要上传的文件
        String fileUrl = "C:\\Users\\work\\Desktop/2.jpg";

        String ip = "";
        String port = "";

        uploadImage(fileUrl, ip, port);
    }

    private static void uploadImage(String fileUrl, String ip, String port) {
        // appkey,固定，
        String cappKey = "appkey1";
        // 秘钥，固定
        String secret = "sdfajk3242324fa!djq7";

        // 时间戳，用户自己生成
        String ctimestamp = System.currentTimeMillis() + "";

        // 6位随机码，用户自己生成
        String cnonce = getStringRandom();

        String requestParam = "";

        // 请求方式,看要请求的接口说明
        String method = "POST";

        // 计算签名
        String csign = SignUtlis.sign(ctimestamp, cnonce, "", requestParam, "/api/person/uploadImage", method, cappKey, secret);

        //签名信息
        Map<String, String> files = new HashMap<>();
        files.put("cappkey", "appkey1");
        files.put("cnonce", "1234344");
        files.put("ctimestamp", ctimestamp);
        //files.put("csign", "974228f6c7c56bb1320f8501c01aa991");
        files.put("csign", csign);
        //http 地址请求 ；false 表示
        //String ret = OkHttpUtil.getInstance(false).doPostFormMultipart(ip + ":" + port + "/api/person/uploadImage", fileUrl, files);
        String rets = OkHttpUtil.getInstance(true).doPostFormMultipart(ip + ":" + port + "/api/person/uploadImage", fileUrl, files);
    }
}